// Transform2.cs created with MonoDevelop
// User: werner at 20:10 9-1-2009
//
// To change standard headers go to Edit->Preferences->Coding->Standard Headers
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Drawing2D;
using System.IO;

namespace AdvancedProgramming
{
	public class Transform2
	{

        private enum ACTION {
            COPY = 1001,
            DELETE,
            INSERT,
            SUBST
        }
		
		public Transform2()
		{

		}

        public string Compare(string filename1, string filename2)
        {
            List<string> file1 = FileLoader.LoadFile(filename1);
            List<string> file2 = FileLoader.LoadFile(filename2);
            int[,] matrix = null;
            string s1 = "", s2 = "";

            // put all tekst in a string
            for (int i=0; i<file1.Count; i++)
            {
                s1 += file1[i];
            }

            for (int i = 0; i < file1.Count; i++)
            {
                s2 += file2[i];
            }

            matrix = CalculateDistance(s1, s2);

            List<ACTION> actions = CalculateActions(matrix, s1, s2);

            return ExportMatrixToHTML(matrix, s1.Length, s2.Length);

        }

        private string ExportMatrixToHTML(int[,] matrix, int len1, int len2)
        {
            StringBuilder html = new StringBuilder();

            html.Append("<html>");
            html.Append("<table>");

            for (int i = 0; i < len1+1; i++ )
            {
                html.Append("<tr>");
                for (int j = 0; j < len2+1; j++)
                {
                    html.Append("<td>");
                    html.Append(matrix[i,j]);
                    html.Append("</td>");
                }
                html.Append("</tr>");
            }
            html.Append("</table>");
            html.Append("</html>");

            return html.ToString();
        }

        private List<ACTION> CalculateActions(int[,] matrix, string str1, string str2)
        {
            List<ACTION> actions = new List<ACTION>();
            int prevCost = 0;

            int lenStr1 = str1.Length;
            int lenStr2 = str2.Length;

            for (int i = 1; i <= lenStr1; i++)
            {
                for (int j = 1; j <= lenStr2; j++)
                {
                    prevCost = matrix[i-1, j-1];

                    // als de karakters gelijk zijn, dan is het een copy, met kosten 0
                    int cost = (str2[j - 1] == str1[i - 1]) ? 0 : 1;

                    if (cost == 0)
                    {
                        i++;
                        j++;
                    }
                    else
                    {
                        
                        int costDelete = matrix[i+1, j];
                        int costReplace = matrix[i+1, j+1];
                        int costInsert = matrix[i, j + 1];

                        if (Math.Min( Math.Min(costDelete, costInsert), costReplace) >= costDelete)
                        {
                            actions.Add(ACTION.DELETE);
                            i++;
                        }
                        else if (Math.Min( Math.Min(costDelete, costInsert), costReplace) >= costInsert)
                        {
                            actions.Add(ACTION.INSERT);
                            j++;
                        }
                        else if (Math.Min(Math.Min(costDelete, costInsert), costReplace) >= costReplace)
                        {
                            actions.Add(ACTION.SUBST);
                            i++;
                            j++;
                        }
                    }
                                        
                    
                }
            }

            return actions;
        }

        private int[,] CalculateDistance(string str1, string str2)
        {
            // lengtes van de string opslaan
            int lenStr1 = str1.Length;
            int lenStr2 = str2.Length;

            // initialiseer een matrix van n * m waarbij n=lenStr1+1 en m=lenStr2+1
            int[,] matrix = new int[lenStr1 + 1, lenStr2 + 1];

            for (int i = 0; i <= lenStr1; matrix[i, 0] = i++) ;

            for (int j = 0; j <= lenStr2; matrix[0, j] = j++) ;

            for (int i = 1; i <= lenStr1; i++)
            {
                for (int j = 1; j <= lenStr2; j++)
                {
                    // Bereken de kosten, wanneer het karakter gelijk is (copy), dan zijn de kosten 0 anders 1
                    int cost = (str2[j - 1] == str1[i - 1]) ? 0 : 1;
                    
                    // replace, delete of insert met kosten 1
                    matrix[i, j] = Math.Min(
                        Math.Min(matrix[i - 1, j] + 1, matrix[i, j - 1] + 1),
                        matrix[i - 1, j - 1] + cost);
                    
                }
            }

            return matrix;//[lenStr1, lenStr2];

        }
    }
}
